// **************************************************************
// COPYRIGHT(c)2020, Xidian University
// All rights reserved.
//
// IP LIB INDEX :  
// IP Name      :      
// File name    :  
// Module name  :  
// Full name    :  
// Time         : 2021 
// Author       : Haoxiaofei 
// Email        : 1531804419@qq.com
// Data         : 
// Version      : V 1.0 
// 
// Abstract     :
// Called by    :  
// 
// Modification history
// -----------------------------------------------------------------
// 
// 
//
// *****************************************************************

//*******************
//DEFINE MODULE PORT
//*******************
`include "top_define.v"
module ME2(
    input wire rst_n,
    input wire clk,
    

    //ME与CPU接口
    // input wire[15:0]  ram_addr,
    input wire[31:0]  ram_data,
    input wire        cpu_wen,
    // input wire        cpu_ren,
    // output wire[31:0] read_data_cpu,
    //字段选择接口
    input  wire [0:1023]pktheader_vector,
    input  wire [127:0]ctr_field,
    input  wire        vector_rdy,//字段选择使能

    input  wire schduler_ren,
    output wire [3:0]schduler_i_o,   //优先级[3:0] [3]指定优先级  [2:0]优先级号
    output reg action_en_o,
    output wire [4:0]error
    ); 

//*******************
//DEFINE LOCAL PARAMETER
//*******************
//parameter(s)

//*********************
//INNER SIGNAL DECLARATION
//*********************
//REGS
reg  lookup_done2_ff;
//reg[3:0] schduler_i_ff;
wire [255:0]hash_data;
reg [31:0]hash_data_0;
reg [31:0]hash_data_1;
reg [31:0]hash_data_2;
reg [31:0]hash_data_3;
reg [31:0]hash_data_4;
reg [31:0]hash_data_5;
reg [31:0]hash_data_6;
reg [31:0]hash_data_7;
reg [3:0]hash_data_cnt;
reg[3:0] schduler_data_w,schduler_data_d1,schduler_data_d2,schduler_data_d3;
reg w_en;
//WIRES
wire[4:0] match_res2;
wire[4:0] addra_w;
wire[3:0] schduler_i;
wire lookup_done2;
wire lookup_success2;
wire select_end_o;
//ME2
wire [127:0]rule_in2;

reg cpu_wen_ff;
wire wr_en;
//*********************
//INSTANTCE MODULE
//*********************
//ME2
field_mux_128 U_2(
    .clk(clk),
    .rst_n(rst_n),
    .vector_rdy(vector_rdy),
    .ctr_field(ctr_field),
    .pktheader_vector(pktheader_vector),
    .select_end_o(select_end_o),
    .match_field(rule_in2)
    );

hash_cuckoo U_2_hash(
    .clk(clk),
    .rst_n(rst_n),
    .hash_in(rule_in2),
    .lookup_en(select_end_o),
    .ram_data(hash_data),
    // .ram_addr(ram_addr),
    .cpu_wen(w_en),
    // .cpu_ren(cpu_ren),
    .lookup_done(lookup_done2),
    .lookup_success(lookup_success2),
    .addra_w(addra_w),
    .wea(wea),
    .match_res(match_res2),
    .error(error)
    );
`ifdef ASIC
//rf_2p_d32_w4_wrapper U_schduler_asic(
//  .clk(clk),
//  .wren(wea),
//  .waddr(addra_w),
//  .wdata(schduler_data_w),
//  .rden(1'b1),
//  .raddr(match_res2),
//  .rdata(schduler_i)
//);
tp_rf_4_32 U_schduler(
    .dffs_clk(clk),
    .dffs_rst_n(rst_n),
    .dffs_wen(wea),
    .dffs_waddr(addra_w),
    .dffs_wdata(schduler_data_w),
    .dffs_rden(lookup_done2),
    .dffs_raddr(match_res2),
    .dffs_rdata(schduler_i)
    );
`else
rom_schduler U_schduler(
    .clka(clk),
    .wea(wea),
    .addra(addra_w),
    .dina(schduler_data_w),
    .clkb(clk),
    .addrb(match_res2),
    .doutb(schduler_i)
    );
`endif
//由于第一级ME的绝对延时过大，此处需要缓存ME2的结果，等ME1有结果后则读出
schduler_fifo U_schdulerfifo(
    .clock(clk),
    .rst_n(rst_n),
    .fifo_wen(lookup_done2_ff),
    .fifo_wdata(schduler_i),
    .fifo_ren(schduler_ren),
    .fifo_rdata(schduler_i_o),
    .fifo_empty_rd(),
    .almost_full()
    );
//*********************
//MAIN CORE
//*********************
//hash cpu接口32bit 数据需要打八拍才能形成256bit数据进行配置
always @(posedge clk or negedge rst_n) begin
  if (rst_n == 1'b0) begin
    // reset
   cpu_wen_ff <= 'b0; 
  end
  else begin
   cpu_wen_ff <= cpu_wen; 
  end
end

assign wr_en = cpu_wen & (~cpu_wen_ff);

always@(posedge clk or negedge rst_n) begin
  if(rst_n == 1'b0)
    hash_data_cnt    <= 0;
  else if (wr_en)begin
     if(hash_data_cnt == 7)
       hash_data_cnt    <= 0;
     else
       hash_data_cnt    <= hash_data_cnt + 1;
  end
end
always@(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0) begin
       hash_data_0      <= 32'b0; 
       hash_data_1      <= 32'b0;
       hash_data_2      <= 32'b0;
       hash_data_3      <= 32'b0;
       hash_data_4      <= 32'b0;
       hash_data_5      <= 32'b0;
       hash_data_6      <= 32'b0;
       hash_data_7      <= 32'b0;
       w_en             <= 1'b0;
    end
    else if(wr_en)begin
        if( hash_data_cnt == 0 ) begin
            hash_data_0      <= ram_data;
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 1) begin
            hash_data_0      <= hash_data_0;
            hash_data_1      <= ram_data;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 2) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= ram_data;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 3) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= ram_data;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 4) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= ram_data;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 5) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= ram_data;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 6) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= ram_data;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
        end
        else if (hash_data_cnt == 7) begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= ram_data;
            w_en             <= 1'b1;
        end
        else begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= w_en;
        end
    end
    else begin
            hash_data_0      <= hash_data_0; 
            hash_data_1      <= hash_data_1;
            hash_data_2      <= hash_data_2;
            hash_data_3      <= hash_data_3;
            hash_data_4      <= hash_data_4;
            hash_data_5      <= hash_data_5;
            hash_data_6      <= hash_data_6;
            hash_data_7      <= hash_data_7;
            w_en             <= 1'b0;
    end
end
assign hash_data = {hash_data_0,hash_data_1,hash_data_2,hash_data_3,hash_data_4,hash_data_5,hash_data_6,hash_data_7}; 
//2021.9.1  HXF 
always@(posedge clk or negedge rst_n)
  if(!rst_n)
    begin 
 //     schduler_i_ff   <= 'b0;
      lookup_done2_ff <= 'b0;
    end 
  else begin 
 //     schduler_i_ff     <= schduler_i;
      lookup_done2_ff   <= lookup_done2;
  end

always@(posedge clk or negedge rst_n) begin 
  if(!rst_n) begin 
      schduler_data_d1 <= 4'b0;
  end 
  else if(w_en)begin 
      schduler_data_d1   <= hash_data[3:0];
  end
end 
always@(posedge clk or negedge rst_n) begin 
  if(!rst_n) begin 
      schduler_data_d2 <= 4'b0;
      schduler_data_d3 <= 4'b0;
      schduler_data_w  <= 4'b0;
  end 
  else begin 
      schduler_data_d2   <= schduler_data_d1;
      schduler_data_d3   <= schduler_data_d2;
      schduler_data_w    <= schduler_data_d3;
  end
end

always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    // reset
    action_en_o <= 1'b0;
  end
  else if (schduler_ren) begin
    action_en_o <= 1'b1;
  end
  else  begin
    action_en_o <= 1'b0;
  end
end


//*********************
endmodule    // hookup byte controller block
